Skip to content

Type safe option value getter #14561

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

dcbaker
Copy link
Member

@dcbaker dcbaker commented May 5, 2025

This (ultimately) makes the OptionStore.get_option_value() type safe, but using a generic with a bound type. This allows us to both have runtime type checking, and allows mypy (and other type checkers) to see that at static inspection time and treat the return as safe. This, in turn, allows us to remove a lot of assert isinstance(...), 'for mypy' checks, with a proper MesonBugException with a more helpful error message.

The addition of a fallback parameter also allows us to remove a bunch of if key in options and options.get_value_for(key) style checks, through the use of the fallback.

This series has been split into a bunch of patches to attempt to make review easier, but I'm perfectly happy to squash any number of them into less patches before merging.

Copy link
Member

@bruchar1 bruchar1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a typo in the fourth commit message: envrionment.

I don't see the value of using separate commits for each file. Personally, I would rather squash all of them.

@dcbaker
Copy link
Member Author

dcbaker commented May 6, 2025

I don't see the value of using separate commits for each file. Personally, I would rather squash all of them.

Yeah, I didn't plan to merge them that way, just have smaller chunks to review

@dcbaker dcbaker force-pushed the submit/type-safe-option-value-getter branch 2 times, most recently from 85f0d3b to 6431122 Compare May 6, 2025 20:40
This provides a variant of `get_value_for` that does run-time type
checking, but in a way that allows static type checkers like mypy to
understand. This gives us the two fold advantage of runtime checking of
types that can't be statically known and not having to write a lot
`assert isinstance(...), 'for mypy'` checks.
@dcbaker dcbaker force-pushed the submit/type-safe-option-value-getter branch from 6431122 to 245c47f Compare May 15, 2025 19:07
@dcbaker dcbaker marked this pull request as draft May 15, 2025 19:08
dcbaker added 8 commits May 16, 2025 10:21
It belongs here, rather than in the CoreData.
We have a fallback parameter now, so we can avoid the exception handling
by providing a sane or sentinel default value instead
This pattern repeats a lot in the Compiler, and the compiler even has
it's own implementation of this (which will be removed shortly).
This was an unsafe version of the other function, but without proper
subproject handling. In most cases (except unittests) the safe variant
was actually better anyway, especially with the fallback parameter
@dcbaker dcbaker force-pushed the submit/type-safe-option-value-getter branch from 245c47f to c62617e Compare May 16, 2025 17:57
@@ -889,7 +890,19 @@ def get_value_object_and_value_for(self, key: OptionKey) -> T.Tuple[AnyOptionTyp
computed_value = vobject.validate_value(self.augments[key])
return (vobject, computed_value)

def get_value_for(self, name: 'T.Union[OptionKey, str]', subproject: T.Optional[str] = None) -> ElementaryOptionValues:
def get_value_for(self, key: OptionKey, type_: T.Type[ElementaryOptionTypes],
*, fallback: T.Optional[ElementaryOptionTypes] = None) -> ElementaryOptionTypes:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe default would be more in line to how the same concept is named in the Pyrthon APIs than fallback

@@ -1161,7 +1161,7 @@ def get_default_for_b_option(self, key: OptionKey) -> ElementaryOptionValues:
assert self.is_base_option(key)
try:
return T.cast('ElementaryOptionValues', COMPILER_BASE_OPTIONS[key.evolve(subproject=None)].default)
except KeyError:
except KeyErrorexcept Key:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something went wrong here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants